package com.xunqi.mall.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xunqi.mall.enums.OrderStatusEnum;
import com.xunqi.mall.enums.PaymentTypeEnum;
import com.xunqi.mall.enums.ProductStatusEnum;
import com.xunqi.mall.enums.ResponseEnum;
import com.xunqi.mall.mapper.OrderItemMapper;
import com.xunqi.mall.mapper.OrderMapper;
import com.xunqi.mall.mapper.ProductMapper;
import com.xunqi.mall.mapper.ShippingMapper;
import com.xunqi.mall.pojo.*;
import com.xunqi.mall.service.CartService;
import com.xunqi.mall.service.OrderService;
import com.xunqi.mall.vo.OrderItemVo;
import com.xunqi.mall.vo.OrderVo;
import com.xunqi.mall.vo.ResponseVo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Created with IntelliJ IDEA.
 * @author: 夏沫止水
 * @create: 2020-04-24 09:46
 **/
@Service("orderService")
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private ShippingMapper shippingMapper;

    @Resource
    private CartService cartService;

    @Resource
    private ProductMapper productMapper;

    @Resource
    private OrderItemMapper orderItemMapper;

    /**
     * 创建订单
     * @param uid
     * @param shippingId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseVo<OrderVo> addOrder(Integer uid, Integer shippingId) {

        //先获取收货人信息
        Shipping shipping = shippingMapper.selectByIdAndUserId(shippingId, uid);
        if (shipping == null) {
            return ResponseVo.error(ResponseEnum.SHIPPING_NOT_EXISTS);
        }

        //获取购物车商品，效验(是否有商品，库存是否充足)
        //针对只选中的商品
        List<Cart> cartList = cartService.listForCart(uid).stream()
                .filter(e -> e.getProductSelected()).collect(Collectors.toList());

        //判断购物车里的商品是否为空
        if (CollectionUtils.isEmpty(cartList)) {
            return ResponseVo.error(ResponseEnum.CART_SELECT_IS_EMPTY);
        }

        //获取cartList里的productIds
        Set<Integer> productIdSet = cartList.stream()
                .map(e -> e.getProductId()).collect(Collectors.toSet());

        //查询数据库里的商品信息
        List<Product> productList = productMapper.selectByProductIdSet(productIdSet);

        //将productList转换成map对象
        Map<Integer, Product> productMap = productList.stream()
                .collect(Collectors.toMap(e -> e.getId(), product -> product));

        //生成orderNo订单编号
        Long orderNo = generateOrderNo();
        List<OrderItem> orderItemList = new ArrayList<>();
        //循环购物车里所存在的商品信息
        for (Cart cart : cartList) {
            //根据购物车里面的商品id查询商品信息
            Product product = productMap.get(cart.getProductId());
            //是否有商品
            if (product == null) {
                return ResponseVo.error(ResponseEnum.PRODUCT_NOTEXIST,"商品不存在,productId=" + cart.getProductId());
            }

            //商品的上下架状态
            if (!ProductStatusEnum.ON_SALE.getCode().equals(product.getStatus())) {
                return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETE,"商品不是在售状态" + product.getName());
            }
            //库存是否充足
            if (product.getStock() < cart.getQuantity()) {
                return ResponseVo.error(ResponseEnum.PRODUCT_NOT_STOCK,"库存不正确" + product.getName());
            }

            //构建BuilderOrderItem对象
            OrderItem orderItem = builderOrderItem(uid, orderNo, cart.getQuantity(), product);
            orderItemList.add(orderItem);

            //减库存
            product.setStock(product.getStock() - cart.getQuantity());
            //将数据更新到数据库中去
            int updateProduct = productMapper.updateByPrimaryKeySelective(product);
            if (updateProduct <= 0) {
                return ResponseVo.error(ResponseEnum.ERROR);
            }
        }

        //计算总价格,只计算被选中的商品
        //构建BuilderOrder对象
        Order order = builderOrder(uid, orderNo, shippingId, orderItemList);

        //生成订单，入库:order和order_item,采用事务
        int orderResult = orderMapper.insertSelective(order);
        if (orderResult <= 0) {
            return ResponseVo.error(ResponseEnum.ERROR);
        }

        //批量新增
        int orderItemResult = orderItemMapper.batchInsert(orderItemList);
        if (orderItemResult <= 0) {
            return ResponseVo.error(ResponseEnum.ERROR);
        }

        //更新购物车(选中的商品)
        //操作Redis,不能回滚
        for (Cart cart : cartList) {
            //把Redis的缓存数据删除
            cartService.deleteCart(uid,cart.getProductId());
        }

        //返回给前端，构造orderVo对象
        OrderVo orderVo = builderOrderVo(order, orderItemList, shipping);

        //最终返回orderVo对象
        return ResponseVo.success(orderVo);
    }

    /**
     * 查询订单列表
     *
     * @param uid
     * @param pageSize
     * @param pageNum
     * @return
     */
    @Override
    public ResponseVo<PageInfo> orderList(Integer uid, Integer pageSize, Integer pageNum) {

        //添加分页条件
        PageHelper.startPage(pageSize,pageNum);

        //根据用户id查询所有订单详细列表
        List<Order> orderList = orderMapper.selectAllByUid(uid);

        if (CollectionUtils.isEmpty(orderList)) {
            return ResponseVo.error(ResponseEnum.ORDER_LIST_EXISTS);
        }

        //取出orderNo集合
        Set<Long> orderNoSet = orderList.stream().map(e -> e.getOrderNo()).collect(Collectors.toSet());

        //查询多个订单列表
        List<OrderItem> orderItemList = orderItemMapper.selectByOrderNoSet(orderNoSet);

        //将list集合转换成map集合
        Map<Long, List<OrderItem>> orderItemMap = orderItemList.stream().
                collect(Collectors.groupingBy(e -> e.getOrderNo()));

        //从orderList集合中获取shippingId
        Set<Integer> shippingIdSet = orderList.stream().
                map(e -> e.getShippingId()).collect(Collectors.toSet());

        //根据shippingIdSet查询收货人信息
        List<Shipping> shippingList = shippingMapper.selectByIdSet(shippingIdSet);
        Map<Integer, Shipping> shippingMap = shippingList.stream().
                collect(Collectors.toMap(e -> e.getId(), shipping -> shipping));

        List<OrderVo> orderVoList = new ArrayList<>();

        //构造orderVo对象
        for (Order order : orderList) {
            List<OrderItem> orderItemNoList = orderItemMap.get(order.getOrderNo());
            Shipping shipping = shippingMap.get(order.getShippingId());
            OrderVo orderVo = builderOrderVo(order, orderItemNoList, shipping);
            orderVoList.add(orderVo);
        }

        PageInfo pageInfo = new PageInfo(orderList);
        pageInfo.setList(orderVoList);


        return ResponseVo.success(pageInfo);
    }

    /**
     * 根据订单编号查询订单详情
     * @param uid
     * @param orderNo
     * @return
     */
    @Override
    public ResponseVo<OrderVo> detailOrder(Integer uid, Long orderNo) {

        //根据订单编号查询订单信息
        Order order = orderMapper.selectByOrderNo(orderNo);

        //判断订单是否存在或者是订单是否属于当前用户
        if (order == null || !order.getUserId().equals(uid)) {
            return ResponseVo.error(ResponseEnum.ORDER_LIST_EXISTS);
        }

        //查询订单子模块
        List<OrderItem> orderItemList = orderItemMapper.selectByOrderNo(orderNo);

        //查询收货人地址
        Shipping shipping = shippingMapper.selectByPrimaryKey(order.getShippingId());

        //构造orderVo对象
        OrderVo orderVo = builderOrderVo(order, orderItemList, shipping);

        return ResponseVo.success(orderVo);
    }

    /**
     * 根据订单编号取消该订单
     * @param uid
     * @param orderNo
     * @return
     */
    @Override
    public ResponseVo cancelOrder(Integer uid, Long orderNo) {

        Order order = orderMapper.selectByOrderNo(orderNo);
        //判断订单是否存在或者是订单是否属于当前用户
        if (order == null || !order.getUserId().equals(uid)) {
            return ResponseVo.error(ResponseEnum.ORDER_LIST_EXISTS);
        }

        //只有未付款订单可以取消
        if (!order.getStatus().equals(OrderStatusEnum.NOT_PAY)) {
            return ResponseVo.error(ResponseEnum.ORDER_STATUS_ERROR);
        }

        //修改订单状态
        order.setStatus(OrderStatusEnum.CANCELED.getCode());
        //设置关闭时间
        order.setCloseTime(new Date());
        //更新到数据库中
        int updateResult = orderMapper.updateByPrimaryKeySelective(order);

        if (updateResult <= 0) {
            return ResponseVo.error(ResponseEnum.ERROR);
        }

        return ResponseVo.success();
    }

    /**
     * 修改订单支付状态
     * @param orderNo
     * @return
     */
    @Override
    public void paid(Long orderNo) {
        //根据订单号查询订单
        Order order = orderMapper.selectByOrderNo(orderNo);

        //判断订单是否存在或者是订单是否属于当前用户
        if (order == null) {
            throw new RuntimeException(ResponseEnum.ORDER_LIST_EXISTS.getMsg() + "订单id：" + orderNo);
        }

        //只有未付款订单可以变成已付款
        if (!OrderStatusEnum.NOT_PAY.getCode().equals(order.getStatus())) {
            throw new RuntimeException(ResponseEnum.ORDER_STATUS_ERROR.getMsg() + "订单id：" + orderNo);
        }

        //修改订单状态为已支付
        order.setStatus(OrderStatusEnum.PAID.getCode());
        //设置关闭时间
        order.setPaymentTime(new Date());

        int updateResult = orderMapper.updateByPrimaryKeySelective(order);

        if (updateResult <= 0) {
            throw new RuntimeException("将订单更新为已支付状态失败" + "订单id：" + orderNo);
        }
    }

    /**
     * 构造orderVo对象
     * @param order
     * @param orderItemList
     * @param shipping
     * @return
     */
    private OrderVo builderOrderVo(Order order, List<OrderItem> orderItemList, Shipping shipping) {

        OrderVo orderVo = new OrderVo();
        BeanUtils.copyProperties(order,orderVo);

        //将orderItemList转换为orderItemVoList
        List<OrderItemVo> orderItemVoList = orderItemList.stream().map(e -> {
            OrderItemVo orderItemVo = new OrderItemVo();
            BeanUtils.copyProperties(e, orderItemVo);
            return orderItemVo;
        }).collect(Collectors.toList());

        orderVo.setOrderItemVoList(orderItemVoList);
        //判断用户地址信息是否存在(避免出现空指针异常)
        if (shipping != null) {
            orderVo.setShippingId(shipping.getId());
        }
        orderVo.setShippingVo(shipping);
        return orderVo;
    }

    /**
     * 构建BuilderOrder对象
     * @param uid
     * @param orderNo
     * @param shippingId
     * @param orderItemList
     */
    private Order builderOrder(Integer uid,
                               Long orderNo,
                               Integer shippingId,
                               List<OrderItem> orderItemList) {

        //使用stream流遍历计算商品总价格
        BigDecimal payment = orderItemList.stream().map(e -> e.getTotalPrice())
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        Order order = Order.builder()
                .orderNo(orderNo)
                .userId(uid)
                .shippingId(shippingId)
                .payment(payment)
                .paymentType(PaymentTypeEnum.PAY_ONLINE.getCode())
                .postage(0)
                .status(OrderStatusEnum.NOT_PAY.getCode())
                .paymentTime(new Date())
                .createTime(new Date())
                .updateTime(new Date())
                .build();

        return order;

    }

    /**
     * 构建BuilderOrderItem对象
     * @param uid
     * @param orderNo
     * @param quantity
     * @param product
     * @return
     */
    private OrderItem builderOrderItem(Integer uid, Long orderNo, Integer quantity, Product product) {

        OrderItem orderItem = OrderItem.builder()
                .userId(uid)
                .orderNo(orderNo)
                .productId(product.getId())
                .productName(product.getName())
                .productImage(product.getMainImage())
                .currentUnitPrice(product.getPrice())
                .quantity(quantity)
                .totalPrice(product.getPrice().multiply(BigDecimal.valueOf(quantity)))
                .createTime(new Date())
                .updateTime(new Date())
                .build();

        return orderItem;

    }

    //生成订单编号
    private Long generateOrderNo() {
        return System.currentTimeMillis() + new Random().nextInt(999);
    }
}
